695. Range Variation Query

 

The sequence an is given with the formula: an = n2 mod 12345 + n3 mod 23456.

You need to answer the next queries a lot of times:

·        find the difference between the maximum and the minimum element among the values ai, ai + 1, ..., aj;

·        assign to the element ai the value of j.

 

Input. The first line contains the number of queries k (k ≤ 100 000). Each of the next k lines contains one query. The i-th query contains the numbers xi, yi.

If xi > 0, find the difference between the maximum and the minimum element among the values of axi...ayi. It is known that 1 ≤ xiyi ≤ 100 000.

If xi < 0, assign to the element a-xi the value of yi. It is known that -100 000 ≤ xi ≤ -1 and |yi| ≤ 100 000.

 

Output. For each query of the first type print in a separate line the difference between the maximum and the minimum element on a given segment.

 

Sample input

7

1 3

2 4

-2 -100

1 5

8 9

-3 -101

2 3

 

Sample output

34

68

250

234

1

 

 

SOLUTION

data structures – segment tree

 

Algorithm analysis

Поскольку в задаче присутствует модификация элементов, то ее можно рассматривать как задачу динамического RMQ и следует решать при помощи дерева отрезков. Для этого необходимо реализовать следующие функции:

·        создание дерева отрезков по массиву а;

·        нахождение минимума и максимума на отрезке;

·        единичную модификацию элемента.

Реализовать дерево отрезков можно как при помощи дерева, так и линейного массива.

 

Example

Положим a0 = 0. Сгенерируем первые 10 элементов последовательности ai:

i

0

1

2

3

4

5

6

7

8

9

10

ai

0

2

12

36

80

150

252

392

576

810

1100

 

Выполним запросы, приведенные в примере:

1 3

max[1..3] – min[1..3] = 36 – 2 = 34

2 4

max[2..4] – min[2..4] = 80 – 12 = 68

-2 -100

a2 = -100

1 5

max[1..5] – min[1..5] = 150 – (-100) = 250

8 9

max[8..9] – min[8..9] = 810 – 576 = 234

-3 -101

a3 = -101

2 3

max[2..3] – min[2..3] = -100 – (-101) = 1

 

Algorithm realization

Дерево отрезков храним в векторе SegmentTree длины 4*MAX, где MAX – максимальное количество элементов, которое может храниться в отрезке. Структура node хранит минимальное min и максимальное max значение на отрезке.

 

#define MAX 100000

struct node

{

  int min, max;

} SegmentTree[4*MAX];

 

На вход процедуре build построения дерева отрезков передается массив a, номер текущей вершины дерева Vertex и границы отрезка Left и Right, соответствующие вершине Vertex.

 

void BuildTree(int *a, int Vertex, int Left, int Right)

{

  if (Left == Right)

    SegmentTree[Vertex].min = SegmentTree[Vertex].max = a[Left];

  else

  {

    int Middle = (Left + Right) / 2;

    BuildTree(a, 2*Vertex, Left, Middle);

    BuildTree(a, 2*Vertex+1, Middle+1, Right);

 

Пересчитываем минимальное и максимальное значение на отрезке [Left, Right], используя информацию сыновей вершины Vertex.

 

    SegmentTree[Vertex].min = 

       min(SegmentTree[2*Vertex].min,SegmentTree[2*Vertex+1].min);

    SegmentTree[Vertex].max =

       max(SegmentTree[2*Vertex].max,SegmentTree[2*Vertex+1].max);

  }

}

 

Вершине Vertex соответствует отрезок [LeftPos; RightPos]. Функция GetMin возвращает минимум на отрезке [Left; Right].

 

int GetMin(int Vertex, int LeftPos, int RightPos, int Left, int Right)

{

  if (Left > Right) return INF;

  if ((Left == LeftPos) && (Right == RightPos))

    return SegmentTree[Vertex].min;

  int Middle = (LeftPos + RightPos) / 2;

  return min(GetMin(2*Vertex, LeftPos, Middle, Left, min(Right,Middle)),

           GetMin(2*Vertex+1, Middle+1, RightPos, max(Left,Middle+1),Right));

}

 

Вершине Vertex соответствует отрезок [LeftPos; RightPos]. Функция GetMax возвращает максимум на отрезке [Left; Right].

 

int GetMax(int Vertex, int LeftPos, int RightPos, int Left, int Right)

{

  if (Left > Right) return -INF;

  if ((Left == LeftPos) && (Right == RightPos))

    return SegmentTree[Vertex].max;

 

  int Middle = (LeftPos + RightPos) / 2;

  return max(GetMax(2*Vertex, LeftPos, Middle, Left, min(Right,Middle)),

           GetMax(2*Vertex+1, Middle+1, RightPos, max(Left,Middle+1),Right));

}

 

Вершине Vertex соответствует отрезок [LeftPos; RightPos]. Функция Update присваивает элементу с индексом Position значение NewValue.

 

void Update(int Vertex, int LeftPos, int RightPos,

            int Position, int NewValue)

{

 

Если вершине Vertex соответствует отрезок, состоящий из одного элемента (LeftPos равно RightPos), то мы дошли до листа дерева отрезков. Минимум и максимум на отрезке, состоящего из одного элемента, равен NewValue.

 

       if (LeftPos == RightPos)

    SegmentTree[Vertex].min = SegmentTree[Vertex].max = NewValue;

  else

  {

 

Иначе вычисляем, в каком – левом или правом сыне вершины Vertex лежит элемент с индексом Position. Запускаем рекурсивно его модификацию.

 

    int Middle = (LeftPos + RightPos) / 2;

    if (Position <= Middle)

      Update (2*Vertex, LeftPos, Middle, Position, NewValue);

    else

      Update (2*Vertex+1, Middle+1, RightPos, Position, NewValue);

 

Пересчитываем значение минимума min и максимума max в текущей вершине Vertex дерева отрезков.

 

    SegmentTree[Vertex].min =

      min(SegmentTree[2*Vertex].min,SegmentTree[2*Vertex+1].min);

    SegmentTree[Vertex].max =

      max(SegmentTree[2*Vertex].max,SegmentTree[2*Vertex+1].max);

  }

}

 

Основная часть программы. Генерируем последовательность ai согласно приведенной в условии задаче формуле. Последовательность храним в массиве int a[MAX+1];

 

  for(i = 0; i <= MAX; i++)

    a[i] = (i * i) % 12345 + ((i * i) % 23456 * i) % 23456;

 

Строим дерево отрезков.

 

BuildTree(a,1,0,MAX);

 

Читаем входные данные и отвечаем на запросы.

 

scanf("%d",&k);

while(k--)

{

  scanf("%d %d",&x,&y);

  if (x > 0) printf("%d\n",GetMax(1,0,MAX,x,y) - GetMin(1,0,MAX,x,y));

  else Update(1,0,MAX,-x,y);

}